﻿//#define _CRT_SECURE_NO_WARNINGS 1
//#include<bits/stdc++.h>
//using namespace std;
////http://www.oj7.cn/
//int n, m, f[100005][105];
//struct node
//{
//	int wi, vi;
//}Goods[135];
//int main()
//{
//	cin >> m >> n;
//	for (int i = 1; i <= n; i++)
//	{
//		cin >> Goods[i].wi >> Goods[i].vi;
//	}
//	for (int i = 1; i <= n; i++)
//	{
//		for (int v = m; v > 0; v--)
//		{
//			if (Goods[i].wi <= v)
//			{
//				f[i][v] = max(f[i - 1][v], f[i - 1][v - Goods[i].wi] + Goods[i].vi);
//				/*那么我们可以将dp[0][0...W]初始化为0，表示将前0个物品（即没有物品）装入书包的最大价值为0。那么当 i > 0 时dp[i][j]有两种情况：
//解释一下j-w[i]，这个时候是需要放入第i件物品那么第i件物品需要占用的空间就是w[i]，这个时候背包容量等于j第i件物品占用w[i]就只剩下 j-w[i]，剩下的空间就是留给前i-1件物品，所以我们需要知道f[i-1][j-w[i]]的最大价值加上第i件物品的价值。这就是为什么等于f[i][j]=f[i-1][j-w[i]]+v[i]
//最后我们需要选取两种选择的最大值f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i])
/
//					不装入第i件物品，即dp[i−1][j]；
//					装入第i件物品（前提是能装下），即dp[i−1][j−w[i]] + v[i]。*/
//			}
//			else
//			{
//				f[i][v] = f[i - 1][v];
//			}
//		}
//	}
//	cout << f[n][m] << endl;
//
//	return 0;
//}
//#include<bits/stdc++.h>
//#include <iostream>
//#include <vector>
//using namespace std;
//#define max(N1,N2) N1>N2?N1:N2
//int main()
//{
//	/*
//	第一行输入背包容量V和物体的个数n
//	接下来有n行，每行包含两个数字，分别为该物体的花费和价值
//	*/
//	vector<int> w, v;//w为花费，v为价值
//	vector<vector<int>> f;//f状态矩阵
//	int V, n;//V背包容量，n物体数
//	while (cin >> V >> n)
//	{
//		w.clear();
//		v.clear();
//		f.clear();
//		w.push_back(0);
//		v.push_back(0);
//
//		//输入原始数据
//		for (int i = 1; i <= n; i++)
//		{
//			int cur_w, cur_v;
//			cin >> cur_w >> cur_v;
//			w.push_back(cur_w);
//			v.push_back(cur_v);
//		}
//
//		//初始化状态矩阵
//		for (int i = 0; i <= n; i++)
//		{
//			vector<int> buff(V + 1, 0);
//			f.push_back(buff);
//		}
//
//		//动态规划过程
//		for (int i = 1; i <= n; i++)
//		{
//			for (int j = 0; j <=V; j++)
//			{
//				if (j >= w[i])
//				{
//					f[i][j] = max(f[i - 1][j], f[i-1][j - w[i]] + v[i]);
//				}
//				else
//				{
//					f[i][j] = f[i - 1][j];
//				}
//			}
//		}
//
//		//输出答案
//		int ans = f[n][V];
//		cout << "max="<<ans << endl;
//	}
//	return 0;
//}
//#define _CRT_SECURE_NO_WARNINGS 1
//#include<bits/stdc++.h>
//using namespace std;
////http://www.oj7.cn/
//int n, m, f[100005];
//struct node
//{
//	int wi, vi;
//}Goods[35];
//int main()
//{
//	cin >> m >> n;
//	for (int i = 1; i <= n; i++)
//	{
//		cin >> Goods[i].wi >> Goods[i].vi;
//	}
//	for (int i = 1; i <= n; i++)
//	{
//		for (int v = m; v > 0; v--)
//		{
//			if (Goods[i].wi <= v)
//			{
//				f[v] = max(f[v], f[v - Goods[i].wi] + Goods[i].vi);
//			}
//
//		}
//	}
//	cout << f[m] << endl;
//
//	return 0;
//}
#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>
using namespace std;
//http://www.oj7.cn/
int n, m, f[100005];
struct node
{
	int wi, vi,ki;
}Goods[35];
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> Goods[i].wi >> Goods[i].vi>>Goods[i].ki;
	}
	for (int i = 1; i <= n; i++)
	{
		for (int v = m; v > 0; v--)
		{
			for (int k = 0; k <=Goods[i].ki; k++)
			{
             if (Goods[i].wi <= v)
			{
				f[v] = max(f[v], f[v - k*Goods[i].wi] + k*Goods[i].vi);
			}
		}
			

		}
	}
	cout << f[m] << endl;

	return 0;
}